Encrypted Boot

My Linux laptop uses full disk encryption which makes the boot process slightly more complicated.

Disk Layout

The disk layout:

lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT

NAME                          TYPE    SIZE FSTYPE      MOUNTPOINT
nvme0n1                       disk  476.9G             
├─nvme0n1p1                   part    512M vfat        /boot/efi
├─nvme0n1p2                   part    732M ext4        /boot
├─nvme0n1p3                   part     75G crypto_LUKS 
│ └─nvme0n1p3_crypt           crypt    75G LVM2_member 
│   ├─vgubuntu--budgie-swap_1 lvm       9G swap        [SWAP]
│   └─vgubuntu--budgie-root   lvm      66G ext4        /
└─nvme0n1p4                   part  400.7G crypto_LUKS 
  └─mydata                    crypt 400.7G ext4        /DATA

The setup is as follows:

If you are using full disk encryption or encrypted root partition, a separate /boot partition is necessary. When using encryption, the boot process needs to access the necessary bootloader and kernel from an unencrypted boot partition to allow the system to access files to decrypt the encrypted partitions and start the system. This leaves the boot-loader second stage file-system unencrypted and therefore vulnerable to tampering of the GRUB configuration, Linux kernel or more likely, the initial RAM file-system (initrd.img).

However, GRUB2 is (since Jessie) able to unlock LUKS devices with its cryptomount command, which therefore enables encryption of the /boot partition as well

It is possible, in UEFI Secure Boot mode, to have every stage cryptographically signed, in which case any tampering can be detected and boot aborted. But Secure Boot and Hibernate do not work because something to do with the random signing code and keys for swap decryption.

Boot Order

The UEFI-based platform (i.e. what we used to know as the BIOS, but is now called UEFI) reads the partition table on the system storage and mounts the EFI System Partition (ESP).

  1. UEFI (BIOS)
  2. EFI image (/boot/efi)
  3. GRUB Bootloader
  4. initrd (/boot)
  5. LUKS decryption
  6. Boot

The partition table:

nvme0n1
Device           Size  Type						Mount
/dev/nvme0n1p1   512M  EFI System				/boot/efi
/dev/nvme0n1p2   732M  Linux filesystem         /boot
/dev/nvme0n1p3    75G  Linux filesystem (LUKS)	/ and [SWAP]
/dev/nvme0n1p4   400G  Unknown (LUKS)			Steves Data

UEFI Bootloader

The UEFI-based platform reads the partition table on the system storage and mounts the EFI System Partition (ESP), a VFAT partition labeled with a particular globally unique identifier (GUID). The ESP contains EFI applications such as bootloaders and utility software, stored in directories specific to software vendors. The ESP is /boot/efi/, and EFI software provided by Ubuntu is stored in /boot/efi/EFI/ubuntu/

The /boot/efi/EFI/ubuntu/ directory contains grub64.efi, a version of GRUB (Grand Unified Bootloader) compiled for the EFI firmware architecture as an EFI application. In the simplest case, the EFI boot manager selects grub.efi as the default bootloader and reads it into memory.

EFI System /boot/efi

/boot/efi/EFI:
BOOT
ubuntu

/boot/efi/EFI/BOOT:
BOOTX64.EFI
fbx64.efi
mmx64.efi

/boot/efi/EFI/ubuntu:
BOOTX64.CSV
grub.cfg
grubx64.efi
mmx64.efi
shimx64.efi

GRUB Bootloader

GRUB determines which operating system or kernel to start, loads it into memory, and transfers control of the machine to that operating system. It is the kernel’s job to finish the boot process, including decrypting any disks.

The /boot Partition

/boot
initrd.img
initrd.img-5.15.0-89-generic
System.map-5.15.0-89-generic
vmlinuz
vmlinuz-5.15.0-89-generic
grub/

/boot/grub
grub.cfg

The partition /boot contains the grub config initramfs and vmlinuz.

Grub Config (/boot/grub/grub.cfg)

The config file /boot/grub/grub.cfg is automatically generated by grub-mkconfig. The utility grub-mkconfig (and update-grub) runs shell scripts in /etc/grub.d. One of them is /etc/grub.d/10_linux, which uses the shell function version_find_latest to keep iterating through the list of remaining Linux kernels, from latest to oldest. It also settings from /etc/default/grub file.

To see the menus and submenus available at boot time generated by grub-mkconfig:

awk -F\' '$1=="menuentry " || $1=="submenu " {print i++ " : " $2}; /\smenuentry / {print "\t" i-1">"j++ " : " $2};' /boot/grub/grub.cfg
 
0 : Ubuntu
1 : Advanced options for Ubuntu
	1>0 : Ubuntu, with Linux 5.15.0-89-generic
	1>1 : Ubuntu, with Linux 5.15.0-89-generic (recovery mode)
	1>2 : Ubuntu, with Linux 5.15.0-88-generic
	1>3 : Ubuntu, with Linux 5.15.0-88-generic (recovery mode)
2 : UEFI Firmware Settings

Or for Linux Mint

awk -F\' '$1=="menuentry " || $1=="submenu " {print i++ " : " $2}; /\smenuentry / {print "\t" i-1">"j++ " : " $2};' /boot/grub/grub.cfg

0 : Linux Mint 22.1 Cinnamon
1 : Advanced options for Linux Mint 22.1 Cinnamon

From the GRUB_DEFAULT in /etc/default/grub file we can see which version of Ubuntu will boot if none selected:

/etc/default/grub

# GRUB_DEFAULT="1>2"
GRUB_DEFAULT=0

The actual setting for each Linux option are in the /boot/grub/grub.cfg, which is built by grub-mkconfig which runs script /etc/grub.d/10_linux referencing /etc/fstab and /etc/default/grub:

/etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash resume=/dev/mapper/vgubuntu--budgie-swap_1"

Here is an example for Option 0:

grep vml /boot/grub/grub.cfg

linux	/vmlinuz-5.15.0-89-generic root=/dev/mapper/vgubuntu--budgie-root ro  quiet splash resume=/dev/mapper/vgubuntu--budgie-swap_1 $vt_handoff

But /dev/mapper/vgubuntu--budgie-root is actually encrypted inside nvme0n1p3:

lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID
NAME                  TYPE    SIZE FSTYPE    MOUNTPOINT UUID
nvme0n1               disk  476.9G                      
├─nvme0n1p1           part    512M vfat      /boot/efi  44BA-16B5
├─nvme0n1p2           part    732M ext4      /boot      ad71056c-f2c5-454b-b36a-5ec55f21b226
├─nvme0n1p3           part     75G crypto_LU            b6a7071a-e553-4e95-9544-9dc9ddcfed61
│ └─nvme0n1p3_crypt   crypt    75G LVM2_memb            T25pQf-qlNw-pwNV-5dvg-xOTO-KoKG-tW3CjD
│   ├─vgubuntu--budgie-swap_1
│   │                 lvm       9G swap      [SWAP]     b02b828e-f0bf-4ecb-910a-b88392056049
│   └─vgubuntu--budgie-root
│                     lvm      66G ext4      /          c525d5a2-023a-42af-98fc-0e24b8de4aa3
└─nvme0n1p4           part  400.7G crypto_LU            06124721-121b-4b54-8884-83e439ceb10c
  └─mydata            crypt 400.7G ext4      /DATA      74dbc8a4-f60a-4370-b89f-53d094798864

Physcial volume, volume group and logical volumes:

pvscan
  PV /dev/mapper/nvme0n1p3_crypt   VG vgubuntu-budgie   lvm2 [74.98 GiB / 0    free]
  Total: 1 [74.98 GiB] / in use: 1 [74.98 GiB] / in no VG: 0 [0   ]

vgscan
  Found volume group "vgubuntu-budgie" using metadata type lvm2

lvscan
  ACTIVE            '/dev/vgubuntu-budgie/swap_1' [9.00 GiB] inherit
  ACTIVE            '/dev/vgubuntu-budgie/root'  [65.98 GiB] inherit

So at what point is decryption done?

/etc/crypttab

nvme0n1p3_crypt UUID=b6a7071a-e553-4e95-9544-9dc9ddcfed61 none luks,discard

It would seem that /etc/crypttab is copied into main/cryptroot/crypttab of initrd.img and this causes the boot kernel to prompt for a password for decryption. So /dev/mapper/vgubuntu--budgie-root is available when needed in the boot process.

Initrd/initramfs (/boot)

initrd - is an "initial RAM disk," a temporary root filesystem used in the boot process. The initrd is loaded by the bootloader along with the kernel image and is essential for the two-stage boot process that modern Linux systems use.

To see all files packaged in an the initrd (Init Ram Disk) use the following command.

lsinitramfs "/boot/initrd.img-$(uname -r)"

Note it contains Plymouth files, the graphical loader responsible for Splash screens.

To generate a new initrd use the following command:

update-initramfs -k all -c 

To update initrd after making changes use the following command:

update-initramfs -u

The next boot will use this.